package top.xiaozhaobk.framework.biz.operationlog.aspect;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import top.xiaozhaobk.framework.common.util.JsonUtils;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

@Aspect
@Slf4j
public class ApiOperationLogAspect {
    // 定义切点，拦截带有 ApiOperationLog 注解的方法
    @Pointcut("@annotation(top.xiaozhaobk.framework.biz.operationlog.aspect.ApiOperationLog)")
    public void apiOperationLog() {}

    /**
     * 环绕
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("apiOperationLog()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        //请求时间
        Long startTime = System.currentTimeMillis();

        //获取请求的类和方法
        String simpleName = joinPoint.getTarget().getClass().getSimpleName();
        String methodName = joinPoint.getSignature().getName();

        //请求入参
        Object[] args = joinPoint.getArgs();
        //入参转化为JSON对象
        String argsJsonStr = Arrays.stream(args).map(toJsonStr()).collect(Collectors.joining(","));

        String description = getApiOperationLogDescription(joinPoint);

        //打印请求相应参数
        log.info("====== 请求开始: [{}], 入参: {}, 请求类: {}, 请求方法: {} =================================== ",
                description,argsJsonStr,simpleName,methodName);

        //执行方法
        Object result = joinPoint.proceed();
        //执行耗时
        long executionTime = System.currentTimeMillis() - startTime;
        //打印请求相应参数
        log.info("====== 请求结束: [{}], 出参: {}, 执行耗时: {} =================================== ",
                description,JsonUtils.toJsonString(result),executionTime);
        return result;
    }

    /**
     * 获取注解信息
     * @param joinPoint
     * @return
     */
    public String getApiOperationLogDescription(ProceedingJoinPoint joinPoint) throws Throwable {
        //获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //获取被标记注解的方法
        Method method = signature.getMethod();
        //提取当前方法的注解信息
        ApiOperationLog annotation = method.getAnnotation(ApiOperationLog.class);
        //返回当前注解的 description 信息
        return annotation.description();
    }

    /**
     * 转 JSON 字符串
     * @return
     */
    @SneakyThrows
    private Function<Object, String> toJsonStr() {
        return JsonUtils::toJsonString;
    }
}
